package api

import (
	"errors"
	"fmt"
	"reflect"
	"service/app/mode"
	"service/global"
	"service/utils"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
)

type BaseApi struct {
	Ctx     *gin.Context
	Logger  *zap.SugaredLogger
	BaseErr error
}

func (m BaseApi) BaseApiInit() *BaseApi {
	return &BaseApi{
		Logger: global.Logger,
	}
}

type IBaseApiParams struct {
	Ctx *gin.Context
	Dto any
	// uri
	ReqUri bool
	ReqQey bool
	// uri与body
	AllParams bool
	// 验证规则
	Valid bool
}

func (m *BaseApi) AddBaseErr(err error) {
	appendErr := utils.AppendError(m.BaseErr, err)
	m.BaseErr = appendErr
}
func (m BaseApi) GetBaseErr() error {
	return m.BaseErr
}

func (m *BaseApi) NoParam(ctx *gin.Context) {
	m.Ctx = ctx
}

// 上下文解析参数 给后面的逻辑一个信号,不传指针
func (m *BaseApi) BaseReqHandle(param *IBaseApiParams) *BaseApi {
	var paramErr error
	m.Ctx = param.Ctx
	if param.ReqQey {
		paramErr = m.Ctx.ShouldBindQuery(param.Dto)
	} else {
		if param.AllParams || param.ReqUri {
			// TODO Param可能会错
			paramErr = utils.AppendError(paramErr, m.Ctx.ShouldBindUri(param.Dto))
		}
		if param.AllParams || !param.ReqUri {
			paramErr = utils.AppendError(paramErr, m.Ctx.ShouldBindBodyWithJSON(param.Dto))
			// paramErr = utils.AppendError(paramErr, m.Ctx.ShouldBindJSON(param.Dto))
		}
	}
	// 验证规则
	if param.Valid {
		err := m.validObj(param.Dto)
		if err != nil {
			paramErr = utils.AppendError(paramErr, err)
		}
	}

	if paramErr != nil {
		errMsg := invalidMsg(paramErr, param.Dto)
		// 向结构体储存错误
		m.AddBaseErr(errMsg)
		// m.Fail(ResponseJson{Msg: m.GetBaseErr().Error()})
	}
	return m
}

func invalidMsg(customerr error, target any) error {
	var errList error
	entity := reflect.TypeOf(target)
	// 断言 只处理 params错误
	if file, ok := customerr.(validator.ValidationErrors); !ok {
		return customerr
	} else {
		for i := 0; i < len(file); i++ {
			item := file[i]
			// 错误项
			field, _ := entity.Elem().FieldByName(item.Field())
			// item.Field() 每一项的名 ,item.Tag() 错误的tag名
			// 实体中取出tag
			// fmt.Printf("field.Tag %v", field.Tag.Get(item.Field()))
			// fmt.Printf("field.Tag %v \n", field.Tag.Get(item.Tag()+"_msg"))
			singleError := field.Tag.Get(item.Tag() + "_msg")
			// 设置默认消息
			if singleError == "" {
				// 再从message中获取
				singleError = field.Tag.Get("message")
				if singleError == "" {
					singleError = fmt.Sprintf("验证规则 %s 错误的字段： %s", item.Tag(), item.Field())
				}
			}
			// 将错误强转切片
			errList = utils.AppendError(errList, errors.New(singleError))
		}
	}

	return errList
}

func (m *BaseApi) Okay(resData ResponseJson) {
	Okay(m.Ctx, resData)
}

func (m *BaseApi) Fail(resData ResponseJson) {
	Fail(m.Ctx, resData)
}

// 服务器错误
func (m *BaseApi) ServerFail(resData ResponseJson) {
	ServerFail(m.Ctx, resData)
}

// 验证数组对象
func (m *BaseApi) validObj(param interface{}) error {
	validate := validator.New()
	err := validate.Struct(param)
	if err != nil {
		return err
	}
	return nil
}

func (m *BaseApi) GetCtxUser() *mode.Lz_user {
	val, exites := m.Ctx.Get("user")
	if !exites {
		m.Fail(ResponseJson{Msg: "用户资料丢失!"})
		return nil
	}
	userInfo, ok := val.(*mode.Lz_user)
	if !ok {
		m.Fail(ResponseJson{Msg: "midware  GetCtxUser 系统错误!"})
		return nil
	}
	return userInfo
}
